package org.dru.clay.configuration;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.lang.reflect.Field;
import java.util.Properties;

public class ClayConfiguration {
	private static final String CLAY_DIR = ".clay";
	private static final String CONFIG = "settings.properties";
	
	private final Properties properties = new Properties();
	private File config;
	
	public ClayConfiguration() {
	}
	
	public void load() {
		final File home = new File(System.getProperty("user.home"));
		if (!home.exists()) {
			throw new RuntimeException("Can't locate user home directory.");
		}
		
		final File clay = new File(home, CLAY_DIR);
		if (!clay.exists()) {
			clay.mkdir();
		}
		
		config = new File(clay, CONFIG);
		if (config.exists()) {
			try {
				final FileInputStream inputStream = new FileInputStream(config);
				properties.load(inputStream);
				inputStream.close();
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
	}
	
	public void save() {
		try {
			final FileOutputStream outputStream = new FileOutputStream(config);
			properties.store(outputStream, "");
			outputStream.close();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	public <T> T get(String namespace, Class<T> configClass) {
		try {
			final T instance = configClass.newInstance();
			for (Field field : configClass.getDeclaredFields()) {
				field.setAccessible(true);
				final String value = properties.getProperty(namespace + "." + field.getName());
				if (value == null) {
					continue;
				}
				final Class<?> fieldType = field.getType();
				
				if (int.class.equals(fieldType) || Integer.class.equals(fieldType)) {
					field.set(instance, Integer.parseInt(value));					
				} else if (long.class.equals(fieldType) || Long.class.equals(fieldType)) {
					field.set(instance, Long.parseLong(value));					
				} else if (float.class.equals(fieldType) || Float.class.equals(fieldType)) {
					field.set(instance, Float.parseFloat(value));					
				} else if (boolean.class.equals(fieldType) || Boolean.class.equals(fieldType)) {
					field.set(instance, Boolean.parseBoolean(value));
				} else if (String.class.equals(fieldType)) {
					field.set(instance, value);
				}
			}
			return instance;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	public <T> T set(String namespace, T instance) {
		try {
			final Class<?> configClass = instance.getClass();
			for (Field field : configClass.getDeclaredFields()) {
				field.setAccessible(true);
				final String key = namespace + "." + field.getName();
				properties.put(key, String.valueOf(field.get(instance)));
			}
			return instance;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}	
}
